#include <windows.h>
#include <tchar.h>
#include "drvmgr.h"

#ifndef _countof
#define _countof(array) (sizeof(array)/sizeof((array)[0]))
#endif 


TCHAR g_acErrorDescription[MAX_PATH*10] = { 0 };

EXTERN_C DWORD LastError()
{
    DWORD dwResult = 0;
    RtlZeroMemory(g_acErrorDescription, sizeof(g_acErrorDescription));
    dwResult = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_MAX_WIDTH_MASK, 
        NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
        g_acErrorDescription, _countof(g_acErrorDescription), NULL
        );
    if (dwResult == 0)
    {
        lstrcpy(g_acErrorDescription, _T("Error number not found."));
    }
    return dwResult;
}

EXTERN_C LPCTSTR GetLastErrorDescription()
{
    return g_acErrorDescription;
}

EXTERN_C BOOL IsDriverRunning(LPCTSTR pszDriverName)
{
	BOOL bResult = FALSE;
	SC_HANDLE hScMgr = NULL;
	SC_HANDLE hDriver = NULL;
	SERVICE_STATUS sest = { 0 }; 

	hScMgr = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
	LastError();
	if (hScMgr)
	{
		hDriver = OpenService(hScMgr, pszDriverName, SERVICE_QUERY_STATUS);
		LastError();
		if (hDriver)
		{
			if (QueryServiceStatus(hDriver,&sest))
			{
				bResult = (sest.dwCurrentState == SERVICE_RUNNING);
			}
			LastError();
			CloseServiceHandle(hDriver);
		}
		CloseServiceHandle(hScMgr);
	}
	return bResult;
}

EXTERN_C BOOL IsExistDriver(LPCTSTR pszDriverName)
{
	BOOL bResult = FALSE;
	SC_HANDLE hScMgr = NULL;
	SC_HANDLE hDriver = NULL;

	hScMgr = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
	LastError();
	if (hScMgr)
	{
		hDriver = OpenService(hScMgr, pszDriverName, SERVICE_START|SERVICE_STOP);
		LastError();
		if (hDriver)
		{
			bResult = TRUE;
			CloseServiceHandle(hDriver);
		}
		CloseServiceHandle(hScMgr);
	}
	return bResult;
}

EXTERN_C BOOL RegisterDriver(LPCTSTR pszDriverName, LPCTSTR pszDriverPath)
{
    BOOL bResult = FALSE;
    SC_HANDLE hScMgr = NULL;
    SC_HANDLE hDriver = NULL;
    
    hScMgr = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
    LastError();
    if (hScMgr)
    {
        hDriver = CreateService(hScMgr, pszDriverName, pszDriverName, 
            0, SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START, SERVICE_ERROR_IGNORE,
                    pszDriverPath, NULL, NULL, NULL, NULL, NULL); 
        LastError();
        if (hDriver)
        {
            CloseServiceHandle(hDriver);
            bResult = TRUE;
        }
        CloseServiceHandle(hScMgr);
    }
    return bResult;
}

EXTERN_C BOOL UnregisterDriver(LPCTSTR pszDriverName)
{
    BOOL bResult = FALSE;
    SC_HANDLE hScMgr = NULL;
    SC_HANDLE hDriver = NULL;

    hScMgr = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
    LastError(); 
    if (hScMgr)
    {
        hDriver = OpenService(hScMgr, pszDriverName, DELETE); 
        LastError(); 
        if (hDriver)
        {
            bResult = DeleteService(hDriver); 
            LastError(); 
            CloseServiceHandle(hDriver); 
        } 
        CloseServiceHandle(hScMgr); 
    }
    return bResult;
}

EXTERN_C BOOL RunDriver(LPCTSTR pszDriverName)
{
    BOOL bResult = FALSE;
    SC_HANDLE hScMgr = NULL;
    SC_HANDLE hDriver = NULL;

	if (IsDriverRunning(pszDriverName))
		return TRUE;

    hScMgr = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
    LastError();
    if (hScMgr)
    {
        hDriver = OpenService(hScMgr, pszDriverName, SERVICE_START);
        LastError();
        if (hDriver)
        {
            bResult = StartService(hDriver, 0, NULL); 
            LastError(); 
            CloseServiceHandle(hDriver);
        }
        CloseServiceHandle(hScMgr);
    }
    return bResult;
}

EXTERN_C BOOL StopDriver(LPCTSTR pszDriverName)
{
    BOOL bResult = FALSE;
    SC_HANDLE hScMgr = NULL;
    SC_HANDLE hDriver = NULL;
    SERVICE_STATUS sest = { 0 }; 

	if (!IsDriverRunning(pszDriverName))
		return TRUE;

    hScMgr = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
    LastError();
    if (hScMgr)
    {
        hDriver = OpenService(hScMgr, pszDriverName, SERVICE_STOP);
        LastError();
        if (hDriver)
        {
            bResult = ControlService(hDriver, SERVICE_CONTROL_STOP, &sest);
            LastError();
            CloseServiceHandle(hDriver);
        }
        CloseServiceHandle(hScMgr);
    }
    return bResult;
}

EXTERN_C BOOL ControlDriver(LPCTSTR pszDriverName, DWORD dwCode, 
                   LPVOID lpInBuffer, DWORD nInBufferSize, 
                   LPVOID lpOutBuffer, DWORD nOutBufferSize, 
                   LPDWORD lpBytesReturned)
{
    BOOL bResult = FALSE;
    SC_HANDLE hScMgr = NULL;
    SC_HANDLE hDriver = NULL;

    TCHAR acBuffer[MAX_PATH] = { 0 };
    DWORD dwBytesReturned = 0;
    DWORD dwOutBytes = 0;
    DWORD dwInBytes = 0;
    HANDLE hFile = INVALID_HANDLE_VALUE;

    TCHAR * pszProfix = NULL;

    {
        DWORD dwVersion = 0; 
        DWORD dwMajorVersion = 0;
        //DWORD dwMinorVersion = 0; 
        
        dwVersion = GetVersion();
        
        // Get the Windows version.
        dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
        //dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));
        
        if (dwMajorVersion >= 5) {
            pszProfix = _T("\\\\.\\Global\\%s");
        } else {
            pszProfix = _T("\\\\.\\%s");
        }
    }
    wsprintf(acBuffer, pszProfix, pszDriverName);

    hFile = CreateFile(acBuffer, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); 
    LastError();
    if (INVALID_HANDLE_VALUE != hFile)
    {
        bResult = DeviceIoControl(hFile, dwCode, 
            lpInBuffer, nInBufferSize, 
            lpOutBuffer, nOutBufferSize, lpBytesReturned, 
            NULL);
        LastError();
        CloseHandle(hFile);
    }

    return bResult;
}
